package com.lwl.concurrency.collection;

import java.util.Date;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * 使用阻塞线程安全的列表
 * 
 * <pre>
 * 阻塞列表与非阻塞列表的主要区别是，阻塞列表有添加和删除元素的方法，
 * 如果由于列表已满或为空而导致这些操作不能立即进行，它们将阻塞调用的线程，
 * 直到这些操作可以进行
 * </pre>
 * 
 * @author lwl 2018年1月16日 下午8:26:31
 */
public class LinkedBlockingDequeTest {
	public static class Client implements Runnable {

		private LinkedBlockingQueue<String> queue;

		public Client(LinkedBlockingQueue<String> queue) {
			this.queue = queue;
		}

		@Override
		public void run() {
			for (int i = 0; i < 3; i++) {
				for (int j = 0; j < 5; j++) {
					StringBuilder request = new StringBuilder();
					request.append(i).append(":").append(j);
					try {
						//如果阻塞度列已满,调用这个方法的线程将阻塞直到列表不为空
						queue.put(request.toString());
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.printf("Client: %s at %s.\n", request, new Date());
				}
				try {
					TimeUnit.SECONDS.sleep(2);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			System.out.printf("Client: End.\n");
		}
	}

	public static void main(String[] args) throws InterruptedException {
		//限制阻塞列表的长度为3
		LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>(3);
		Client client = new Client(queue);
		Thread thread = new Thread(client);
		thread.start();

		for (int i = 0; i < 5; i++) {
			for (int j = 0; j < 3; j++) {
				//waiting if necessary until an element becomes 
				String element = queue.take();
				System.out.println("获取列表元素" + element);
			}
			TimeUnit.MILLISECONDS.sleep(3000);
		}
		System.out.println("等待获取元素");
		String element = queue.take();
		System.out.println(element);
		System.out.println("结束获取元素");
	}

}
